package com.zxmr.hospital.info.action;

import java.util.List;

import com.alibaba.fastjson.JSON;
import com.zxmr.action.Request;
import com.zxmr.action.RequestPayload;
import com.zxmr.action.Response;
import com.zxmr.action.ResponsePayload;
import com.zxmr.action.ResultCode;
import com.zxmr.domain.account.AccountType;
import com.zxmr.domain.account.Role;
import com.zxmr.domain.account.User;
import com.zxmr.domain.service.AuthorizationService;
import com.zxmr.domain.service.UserService;
import com.zxmr.hospital.info.action.dto.EmployeeDTO;
import com.zxmr.navigate.ExecuteException;
import com.zxmr.navigate.Executor;

public class SingleEmployee extends Executor{
	enum method{
		query,
		update,
		add;
	}
	@Override
	public void execute(Request request, Response response) {
		
		try
		{
			method method = Enum.valueOf(method.class, this.getElement().getMethod());
			switch(method)
			{
			case query:
				query(request,response);
				break;
			case update:
				update(request,response);
				break;
			case add:
				add(request,response);
				break;
			}
		}catch(Exception e)
		{
			if(e instanceof ExecuteException)
			{
				sendFailACK(response,e.getMessage());
			}else
			{
				e.printStackTrace();
				sendFailACK(response,"internal error");
			}
			
		}
	
	}
	private void add(Request request, Response response)throws ExecuteException
	{
		// when coming to here Account has be convert to User
		User requestUser = (User)request.getAccount();
		User user = getUserFromJSONFor(request,requestUser);
		// do some basic parameter check
		String validate = user.validate();
		if(!"success".equals(validate))
		{
			throw new ExecuteException(validate);
		}
		checkName(user.getName());
		checkEmail(user.getEmail());
		checkRole(user,requestUser);
		saveUser(user);
		sendACK(response);
	}
	private void sendFailACK(Response response,String message)
	{
		response.setPayload(new ResponsePayload(message));
		response.setResult(ResultCode.COMPONENT_ERROR);
	}
	private void sendACK(Response response)
	{
		response.setPayload(new ResponsePayload("success"));
	}
	private void saveUser(User user) throws ExecuteException
	{
		UserService service = new UserService();
		if(!service.addUser(user))throw new ExecuteException("internal error when save user");
		
		user.setId(service.findUser(user.getName()).getId());
		
		if(!service.setRolesForUser(user, user.getRoles()))
			throw new ExecuteException("error to set role for user");
	}
	private void checkRole(User user,User requestUser)throws ExecuteException
	{
		List<Role> role = user.getRoles();
		if(role == null)return;
		
		for(Role r : role)
		{
			// query DB to check if the role is for the company if not need throw ExecuteException
			AuthorizationService service = new AuthorizationService();
			Role dbRole = service.queryRole(r.getId());
			if(dbRole == null || dbRole.getCompany()!= requestUser.getCompany())
			{
				throw new ExecuteException("role id "+r+" is not exist or you do not authorized to apply role for the user");
			}
		}
	}
	private void checkName(String name) throws ExecuteException
	{
		UserService us = new UserService();
		User user = us.findUser(name);
		if(user !=null )throw new ExecuteException(name+" already exist");
	}
	private void checkEmail(String email)throws ExecuteException
	{
		UserService us = new UserService();
		User user = us.findByEmail(email);
		if(user !=null )throw new ExecuteException(email+" already exist");
	}
	/**
	 * for add function the client will send a json string, this function will convert json string to User object
	 * @param request
	 * @param requestUser
	 * @return
	 * @throws ExecuteException
	 */
	private User getUserFromJSONFor(Request request,User requestUser)throws ExecuteException
	{
		try
		{
			RequestPayload payload = request.getPayload();
			String json = payload.getParameters().get("parameters");
			System.out.println("param "+json);
			EmployeeDTO dto = JSON.parseObject(json, EmployeeDTO.class);
			return mappingDTOtoUser(dto,requestUser);

		}catch(Exception e)
		{
			e.printStackTrace();
			ExecuteException ee = new ExecuteException("json format error");
			throw ee;
		}
	}
	private User mappingDTOtoUser(EmployeeDTO dto,User requestUser)
	{
		User user = new User();
		// this class only user to edit user, not supervisor
		user.setAccountType(AccountType.User);
		user.setStatus(dto.getStatus());
		user.setCompany(requestUser.getCompany());
		
		user.setAge(dto.getAge());
		user.setCell(dto.getCell());
		user.setCollege(dto.getCollege());
		user.setDisplay(dto.getDisplay());
		user.setEducation(dto.getEducation());
		user.setEmail(dto.getEmail());
		user.setName(dto.getName());
		user.setPassword(dto.getPassword());
		user.setSalary(dto.getSalary());
		user.setSex(dto.getSex());
		user.setRoles(dto.getRoles());
		return user;
	}

	private void query(Request request, Response response)throws ExecuteException
	{
		UserService service = new UserService();
		
		User user = queryUserByID(request);
		
		List<Role> roles = service.getAllRole(user);
		
		EmployeeDTO dto = transferUserToDTO(user);
		dto.setRoles(roles);
		
		ResponsePayload payload = new ResponsePayload();
		
		payload.setValue(JSON.toJSONString(dto));
		response.setPayload(payload);
	}
	/**
	 * query User per id and validate the user information
	 * @param request
	 * @return
	 * @throws ExecuteException
	 */
	private User queryUserByID(Request request)throws ExecuteException
	{
		int id;
		try
		{
			id = Integer.parseInt(request.getRequestParameters().get("id"));
			
		}catch(Exception e)
		{
			throw new ExecuteException("parameter error");
		}
		UserService service = new UserService();
		User user = service.findUser(id);
		if(user == null)throw new ExecuteException("can not find user with id "+id);
		
		User requestUser = (User)request.getAccount();
		if(requestUser.getCompany() != user.getCompany())
				throw new ExecuteException("you are not authorized to query the user info");
		
		return user;
	}
	private EmployeeDTO transferUserToDTO(User user)
	{
		EmployeeDTO dto = new EmployeeDTO();
		dto.setPassword(user.getPassword());
		dto.setName(user.getName());
		dto.setDisplay(user.getDisplay());
		dto.setEmail(user.getEmail());
		dto.setAge(user.getAge());
		dto.setCell(user.getCell());
		dto.setCollege(user.getCollege());
		dto.setEducation(user.getEducation());
		dto.setSalary(user.getSalary());
		dto.setSex(user.getSex());
		dto.setStatus(user.getStatus());
		return dto;
	}
	
	private void update(Request request, Response response)throws ExecuteException
	{
		// when coming to here Account has be convert to User
		User requestUser = (User)request.getAccount();
		User user = getUserFromJSONFor(request,requestUser);

		validateUserForUpdate(user,requestUser);
		checkEmailForUpdate(user.getEmail(),user);
		checkRole(user,requestUser);
		updateUser(user);
		sendACK(response);
	}
	private void validateUserForUpdate(User user,User requestUser)throws ExecuteException
	{
		UserService service = new UserService();
		User old = service.findUser(user.getName());
		if(old == null)
			throw new ExecuteException("user name "+user.getName()+" is not exist");
		if(old.getCompany() != requestUser.getCompany())
			throw new ExecuteException("you are not authorized to edit user "+user.getName());

		user.setId(old.getId());
		// do some basic parameter check
		String validate = user.validate();
		if(!"success".equals(validate))
		{
			throw new ExecuteException(validate);
		}
	}
	private void updateUser(User user)throws ExecuteException
	{
		UserService service = new UserService();
		if(!service.updateUser(user))throw new ExecuteException("internal error when save user");
		
		user.setId(service.findUser(user.getName()).getId());
		
		if(!service.setRolesForUser(user, user.getRoles()))
			throw new ExecuteException("error to set role for user");
	}
	private void checkEmailForUpdate(String email,User user)throws ExecuteException
	{
		UserService us = new UserService();
		User user1 = us.findByEmail(email);
		if(user1 !=null && user.getId()!=user1.getId() )throw new ExecuteException(email+" already exist");
	}
}
